%define _IDT_MAC_EXTERN_OR_GLOBAL_ 1
%define _IDT_ASM_ 1

%include"../include/gate.mac" 
%include"../include/idt.mac"   
%include"../include/gdt.mac"
%include"../include/kernel.mac"

;routines to initialize IDT 
[section .text] 
;set tss gate in the idt 
;input: 
;	1.tss_selector.  TSS segment selector,1 word;  
;	2.attr. attributes,1 byte.  
;	3.idt_index.  index in the IDT.  

;Used only for near call 
;stack frame: 
;|tss_selector | 
;|attr		   | 
;|ide_index	   | 
;|eip		   | 

;|ebp		   | (frame pointer)    
idt_set_tss_gate: 
	push ebp 
	mov ebp,esp  
	push eax 
	push ebx 
	push ecx 

	mov ebx,[ebp+8] ;get  idt index  
	shl ebx,3 ;index*8,get offset in the idt   

	mov eax,[ebp+16] ;get tss_selector parameter  
	mov word[idt+ebx+tss_gate_descriptor.tss_selector],ax 

	mov eax,[ebp+12] ;get attributes parameter  
	mov byte[idt+ebx+tss_gate_descriptor.tss_selector],al  

	pop ecx 
	pop ebx 
	pop eax 
	pop ebp 
	ret 12 ;clean up stack  

;set interrupt or trap gate in the idt 

;input: 
;	1.handler. Offset of interrupt routine;  
;	2.selector. Segment Selector; 
;	3.attr. Attributes,1 bytes; 
;	4.idt_index. index in the idt. 

;Used only for near call 
;Stack frame: 
;|handler     | 
;|selector    | 
;|attr		  | 
;|idt_index   | 
;|eip		  |  

;|ebp		| (stack frame pointer)  
idt_set_gate: 
	push ebp 
	mov ebp,esp ;stack frame pointer    
	push eax 
	push ebx 
	push ecx 

	mov ebx,[ebp+8] ;get index 
	shl ebx,3 ;index*8,get offset in the idt  

	mov eax,[ebp+20] ;get interrupt handler  
	mov word[idt+ebx+gate_descriptor.off_low],ax ;low word offset  
	shl eax,16   
	mov word[idt+ebx+gate_descriptor.off_high],ax ;high word offset   

	mov eax,[ebp+16] ;segment selector  
	mov word[idt+ebx+gate_descriptor.selector],ax  

	mov eax,[ebp+12] ;attributes  
	mov byte[idt+ebx+gate_descriptor.attr],al 

	pop ecx 
	pop ebx
	pop eax 
	pop ebp 
	ret 16 ;clean up stack  

;initialize idt by installing exception and trap service routines 
;input:none 

;Used only for near call 
;Stack frame: 
;|eip|  
init_idt_exception_trap: 
	;int 0:divide error   
	INSTALL_EXCP_ROUTINE \
		_divide_error,KERNEL_CODE_SEL,INTR_GATE_ATTR,0  

	;int 2:nmi interrupt   
	INSTALL_EXCP_ROUTINE \
		_nmi_intr,KERNEL_CODE_SEL,INTR_GATE_ATTR,2  

	;int 3:breakpoint 
	INSTALL_EXCP_ROUTINE \
		_breakpoint,KERNEL_CODE_SEL,TRAP_GATE_ATTR,3 

	;int 4:overflow 
	INSTALL_EXCP_ROUTINE \
		_overflow,KERNEL_CODE_SEL,TRAP_GATE_ATTR,4 

	;int 5:BOUND range exceeded 
	INSTALL_EXCP_ROUTINE \
		_bound_range_exceeded,KERNEL_CODE_SEL,INTR_GATE_ATTR,5 

	;int 6:invalid opcode 
	INSTALL_EXCP_ROUTINE \
		_invalid_opcode,KERNEL_CODE_SEL,INTR_GATE_ATTR,6  

	;int 7:device not available(No math coprocessor) 
	INSTALL_EXCP_ROUTINE \
		_device_not_available,KERNEL_CODE_SEL,INTR_GATE_ATTR,7 

	;int 8:double fault 
	INSTALL_EXCP_ROUTINE \
		_double_fault,KERNEL_CODE_SEL,INTR_GATE_ATTR,8 

	;int 9:coprocessor segment overrun  
	INSTALL_EXCP_ROUTINE \
		_coprocessor_seg_overrun,KERNEL_CODE_SEL,INTR_GATE_ATTR,9 

	;int 10:invalid TSS 
	INSTALL_EXCP_ROUTINE \
		_invalid_tss,KERNEL_CODE_SEL,INTR_GATE_ATTR,10 

	;int 11:segment not present 
	INSTALL_EXCP_ROUTINE \
		_segment_not_present,KERNEL_CODE_SEL,INTR_GATE_ATTR,11 

	;int 12:Stack Segment Fault
	INSTALL_EXCP_ROUTINE \
		_stack_fault,KERNEL_CODE_SEL,INTR_GATE_ATTR,12 

	;int 13:General Protection 
	INSTALL_EXCP_ROUTINE \
		_general_protection,KERNEL_CODE_SEL,INTR_GATE_ATTR,13 

	;int 14:page fault 
	INSTALL_EXCP_ROUTINE \
		_page_fault,KERNEL_CODE_SEL,INTR_GATE_ATTR,14 
	

	;int 16:x87 FPU floating-Point Error
	INSTALL_EXCP_ROUTINE \
		_x87_fpu,KERNEL_CODE_SEL,INTR_GATE_ATTR,16 

	;int 17:Alignment check 
	INSTALL_EXCP_ROUTINE \
		_alignment_check,KERNEL_CODE_SEL,INTR_GATE_ATTR,17 
	
	;int 18:Machine Check 
	INSTALL_EXCP_ROUTINE \
		_machine_check,KERNEL_CODE_SEL,INTR_GATE_ATTR,18 

	;int 19:SIMD Floating-Point exception 
	INSTALL_EXCP_ROUTINE \
		_simd,KERNEL_CODE_SEL,INTR_GATE_ATTR,19  
	ret

;initialize idt
;input:none
;output:none
init_idt:
	call init_idt_exception_trap
	LOAD_IDTR load_store_idtr ;load idtr
	ret

[section .data]
load_store_idtr:
	istruc pseudo_descriptor
		at pseudo_descriptor.limit,dw IDT_LEN
		at pseudo_descriptor.base,dd idt
	iend
